<template>
  <view class="mxp-radio-group" :class="[cusClass]" :style="[cusStyle]">
    <mxp-radio
      v-for="(item, index) in newList"
      :key="index"
      :checked="data.checkedValue!.includes(item[valueKey])"
      :index="index"
      :value="item[valueKey]"
      :shape="shape"
      :disabled="disabled || item.disabled || data.interiorLoading"
      :uncheck="typeof item.uncheck === 'boolean' ? item.uncheck : uncheck"
      :iconActiveBackground="iconActiveBackground"
      :iconBackground="iconBackground"
      :iconSize="iconSize"
      :iconActiveColor="iconActiveColor"
      :iconColor="iconColor"
      :label="String(item[labelKey])"
      :labelSize="labelSize"
      :labelActiveColor="labelActiveColor"
      :labelColor="labelColor"
      :labelDisabled="labelDisabled"
      :borderColor="borderColor"
      :borderActiveColor="borderActiveColor"
      :cusStyle="index === 0 ? { marginLeft: 0, ...radioStyle } : radioStyle"
      :iconViewStyle="iconViewStyle"
      :labelViewStyle="labelViewStyle"
      :labelTextStyle="labelTextStyle"
      :beforeChange="beforeChange"
      @change="onChange"
      @update:loading="onBeforeLoading"
    >
      <template #default>
        <slot name="default"></slot>
      </template>
      <template #activeIcon>
        <slot name="activeIcon"></slot>
      </template>
      <template #inactiveIcon>
        <slot name="inactiveIcon"></slot>
      </template>
    </mxp-radio>
  </view>
</template>

<script lang="ts" setup>
  import { type CSSProperties, type PropType, computed, inject, onMounted, shallowReactive, watch } from 'vue';
  import { publicStyeProps } from '../mxp-tool/utils/public-props';
  import type { $AllColorStr, $SizeUnitStr } from '@/mxp-ui/mxp-tool/types/interface';
  import { isObject } from '../mxp-tool/utils/verify';
  import MxpRadio from '@/mxp-ui/mxp-radio/mxp-radio.vue';
  import { type FormID, formInjectKey, formItemPropInjectKey, mxpFormStore } from '../mxp-tool/store/mxp-store-form';

  export type $Item = {
    [x: number | string]: unknown;
    uncheck?: boolean;
    disabled?: boolean;
  };

  defineOptions({
    name: 'mxp-checkbox-list',
  });

  const props = defineProps({
    /** 数组 支持对象数组 和 字符串或数字数组 ：如[1,'3'] 或者 [{label:'aa',value:'bb'}] 为对象数组时可通过 labelKey和 valueKey 自定义显示和实际值的 key */
    list: { type: Array as PropType<($Item | number | string)[]>, default: () => [] },
    /** 形状，square为方形，circle为圆型 */
    shape: { type: String as PropType<'circle' | 'square'>, default: 'square' },
    /** 选中的项目 */
    modelValue: { type: Array as PropType<unknown[]>, default: undefined },
    /** 是否可以取消选中 */
    uncheck: { type: Boolean, default: true },
    /** 当 list传入的 item 为对象时，label 的 key */
    labelKey: { type: String, default: 'label' },
    /** 当 list传入的 item 为对象时，value 的 key */
    valueKey: { type: String, default: 'value' },
    /** 图标的大小 */
    iconSize: { type: String as PropType<$SizeUnitStr>, default: '16px' },
    /** 是否禁用 */
    disabled: { type: Boolean, default: false },
    /** 未选中状态下图标颜色 */
    iconColor: { type: String as PropType<$AllColorStr>, default: '#d6d7d9' },
    /** 选中状态下图标颜色 */
    iconActiveColor: { type: String as PropType<$AllColorStr>, default: '#ffffff' },
    /** 未选中状态的背景颜色 */
    iconBackground: { type: String as PropType<$AllColorStr>, default: '#ffffff' },
    /** 选中状态下的背景颜色 */
    iconActiveBackground: { type: String as PropType<$AllColorStr>, default: undefined },
    /** 边框颜色 */
    borderColor: { type: String as PropType<$AllColorStr>, default: '#d6d7d9' },
    /** 选中状态下的边框颜色 */
    borderActiveColor: { type: String as PropType<$AllColorStr>, default: undefined },
    /** label字体大小 */
    labelSize: { type: String as PropType<$SizeUnitStr>, default: '14px' },
    /** 未选中状态下label的颜色 */
    labelColor: { type: String as PropType<$AllColorStr>, default: '#333333' },
    /** 选中状态下label的颜色 */
    labelActiveColor: { type: String as PropType<$AllColorStr>, default: undefined },
    /** 是否禁止点击提示语选中单选框 */
    labelDisabled: { type: Boolean, default: false },
    /** 每一项的样式 */
    radioStyle: { type: Object as PropType<CSSProperties>, default: () => ({}) },
    /** 图标容器的样式 */
    iconViewStyle: { type: Object as PropType<CSSProperties>, default: () => ({}) },
    /** label容器的样式 */
    labelViewStyle: { type: Object as PropType<CSSProperties>, default: () => ({}) },
    /** label 文本的样式 */
    labelTextStyle: { type: Object as PropType<CSSProperties>, default: () => ({}) },
    /** 状态改变前执行的函数(需要返回 boolean 或者 Promise<boolean>) */
    beforeChange: { type: [Function, undefined] as PropType<((index: number) => Promise<boolean> | boolean) | undefined>, default: undefined },
    ...publicStyeProps,
  });

  defineSlots<{
    /** 主体内容 */
    default?: () => void;
    /** 未选中的图标 */
    activeIcon?: () => void;
    /** 选中的图标 */
    inactiveIcon?: () => void;
  }>();

  const emits = defineEmits<{
    (e: 'change', result: { index: number; modelValue: any; checked: boolean }): void;
    (e: 'update:modelValue', result: Record<string, unknown> | unknown[] | boolean | number | string | undefined): void;
  }>();

  const data = shallowReactive({
    checkedValue: props.modelValue || [],
    interiorLoading: false,
  });

  watch(
    () => props.modelValue,
    (val) => {
      data.checkedValue = val || [];
    }
  );

  let mxpFromIDInjectKey: FormID | undefined = undefined;
  let propInjectKey: number | string | undefined = undefined;
  onMounted(() => {
    mxpFromIDInjectKey = inject<FormID>(formInjectKey);
    propInjectKey = inject<number | string>(formItemPropInjectKey);
  });

  /** 这里把 item 转换为对象形式 */
  const newList = computed<$Item[]>(() => {
    const _list: $Item[] = [];
    props.list.forEach((item) => {
      if (isObject(item)) {
        _list.push({ ...item, [props.labelKey]: props.labelKey in item ? item[props.labelKey] : item });
      } else {
        _list.push({ [props.valueKey]: item, [props.labelKey]: item });
      }
    });
    return _list;
  });

  /**
   * 改变
   */
  function onChange(res: { value: any; checked: boolean; index: number }) {
    if (res.checked) {
      data.checkedValue.push(res.value);
    } else {
      const idx = data.checkedValue.findIndex((item) => res.value === item);
      idx >= 0 && data.checkedValue.splice(idx, 1);
    }

    emits('change', { index: res.index, modelValue: data.checkedValue, checked: res.checked });
    emits('update:modelValue', data.checkedValue);

    // 尝试调用mxp-form组件的验证
    const validateField = mxpFromIDInjectKey ? mxpFormStore().state[mxpFromIDInjectKey]?.validateField : undefined;
    typeof validateField === 'function' && (propInjectKey || propInjectKey === 0) && validateField(propInjectKey, 'change');
  }

  /** 当有改变前的钩织函数时，改变全局禁用状态 */
  function onBeforeLoading(state: boolean) {
    data.interiorLoading = state;
  }
</script>

<style lang="scss" scoped>
  .mxp-radio-group {
    display: flex;
    flex-flow: row wrap;
  }
</style>
